package com.hoperun.checkcloth.net

import com.hoperun.checkcloth.common.SERVER_TIMEOUT
import com.hoperun.checkcloth.common.SERVER_URL
import com.hoperun.checkcloth.common.SOAP_NAMESPACE
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.ksoap2.SoapEnvelope
import org.ksoap2.serialization.SoapObject
import org.ksoap2.serialization.SoapSerializationEnvelope
import org.ksoap2.transport.HttpTransportSE
import kotlin.concurrent.thread
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

class SoapClient(
        private val url: String = SERVER_URL,
        private val timeout: Int = SERVER_TIMEOUT,
        private val nameSpace: String = SOAP_NAMESPACE
) {


    /***
     * 调用服务端方法
     *
     *
     * @param methodName 服务端的方法名，是 SoapAction 的一部分
     * @param param 对应的参数
     * @return 返回服务的响应，是 Soap 的消息文本
     */
    suspend fun makeCall(methodName: String, param: String): CallResult<String> = withContext(Dispatchers.IO) {
        val request = SoapObject(nameSpace, methodName)
        if (param.isNotEmpty()) {
            request.addProperty("arg0", param)
        }
        val envelope = SoapSerializationEnvelope(SoapEnvelope.VER11).apply {
            dotNet = false
            setOutputSoapObject(request)
        }

        val httpTransport = HttpTransportSE(url, timeout).apply { debug = true }

        suspendCoroutine { cont ->
            thread {
                try {
                    httpTransport.call("\"$nameSpace$methodName\"", envelope)
                    if (envelope.response != null) {
                        cont.resume(CallResult(true, envelope.response.toString()))
                    } else {
                        cont.resume(CallResult(false, "response is null"))
                    }
                } catch (e: Exception) {
                    cont.resume(CallResult(false, e.toString()))
                }
            }
        }
    }

}

/***
 * 服务端调用的结果对象
 *
 * @param ok 调用是否成功
 * @param value 如果成功，值是响应对象文本，如果错误值是错误信息
 */
data class CallResult<T>(val ok: Boolean, val value: T)